package net.greyar.theory;

import java.util.List;
import java.util.Map;

public class Absolute extends Symbol {
	public Absolute() {
		strings();
	}
	@Override
	protected StringBuilder toString(StringBuilder sb) {
		int start = sb.length();
		sb.append("(");
		for (int i = 0; i < symbols.size(); i++) {
			symbols.get(i).toString(sb);
			if (i != symbols.size() - 1) {
				sb.append(" ");
			}
		}
		sb.append(")");
		token = sb.substring(start);
		return sb;
	}
	@Override
	protected StringBuilder getPrint(StringBuilder sb) {
		int start = sb.length();
		for (int i = 0; i < symbols.size(); i++) {
			symbols.get(i).getPrint(sb);
			if (i != symbols.size() - 1) {
				sb.append(" ");
			}
		}
		print = sb.substring(start);
		return sb;
	}
	@Override
	public boolean occurs(Variable variable) {
		for (Symbol symbol : symbols) {
			if (symbol.occurs(variable)) {
				return true;
			}
		}
		return false;
	}
	@Override
	public Substitution unify(Symbol other, Substitution sigma) {
		if (other instanceof Expression) {
			return null;
		}
		if (grounds(sigma)) {
			return apply(sigma).unify(other, sigma);
		}
		if (sigma.bound(this)) {
			return sigma.get(this).unify(other, sigma);
		}
		if (other instanceof Variable) {
			if (sigma.bound(other)) {
				return unify(sigma.get(other), sigma);
			} else {
				return sigma.bind(other, this);
			}
		}
		return sigma.constrain(this, other);
	}
	@Override
	public Symbol apply(Substitution sigma, Map<String, Variable> variables) {
		Symbol applied = new Absolute();
		for (Symbol symbol : symbols ) {
			applied.add(symbol.apply(sigma, variables));
		}
		return solve(applied.level().strings());
	}
	private Symbol solve(Symbol applied) {
		try {
			long value = Long.valueOf(applied.get(1).getToken());
			value = value < 0 ? -value : value;
			return new Literal(String.valueOf(value));
		} catch (NumberFormatException e) {
			return applied;
		}
	}
	@Override
	protected List<Variable> getVariables(List<Variable> variables) {
		for (Symbol symbol : symbols) {
			symbol.getVariables(variables);
		}
		return variables;
	}
	@Override
	protected Symbol level() {
		for (int i = 0; i < symbols.size(); i++) {
			symbols.set(i, symbols.get(i).level());
		}
		return this;
	}
	@Override
	protected boolean grounds(Substitution sigma) {
		for (Symbol symbol : symbols) {
			if (!symbol.grounds(sigma)) {
				return false;
			}
		}
		return true;
	}
	@Override
	public String getKey() {
		return "abs";
	}
}
